﻿namespace My.Hydrator.Configuration
{
    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using My.Hydrator.Conventions;
    using My.Hydrator.Helpers;

    public class TypeExpression<TType>
    {
        private readonly ConfigurationExpression configurationExpression;

        public TypeExpression(ConfigurationExpression configurationExpression)
        {
            this.configurationExpression = configurationExpression;
        }

        protected Container Container
        {
            get { return SessionHelper.Container; }
        }

        public void Use<TConvention>() where TConvention : ITypeConvention, new()
        {
            var convention = new TConvention();

            if (convention.Type != typeof(TType) && !typeof(TType).IsNullable(convention.Type))
            {
                throw new ArgumentException();
            }

            var conventionToReplace = this.GetConvention(typeof(TType));
            if (conventionToReplace != null)
            {
                this.Container.Conventions.Remove(conventionToReplace);
            }

            this.Container.Conventions.Add(convention);
        }

        public void Use(ITypeConvention typeConvention) 
        {
            if (typeConvention.Type != typeof(TType) && !typeof(TType).IsNullable(typeConvention.Type))
            {
                throw new ArgumentException();
            }

            var conventionToReplace = this.GetConvention(typeof(TType));
            if (conventionToReplace != null)
            {
                this.Container.Conventions.Remove(conventionToReplace);
            }

            this.Container.Conventions.Add(typeConvention);
        }

        public PropertyExpression<TType, TResult> Property<TResult>(Expression<Func<TType, TResult>> property)
        {
            return new PropertyExpression<TType, TResult>(property);
        }

        private ITypeConvention GetConvention(Type type)
        {
            return this.Container.Conventions.SingleOrDefault(x => x.Type == type);
        }
    }
}
